home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World's Largest Collection of Windows Software
/
The World's Largest Collection of Windows Software - Disc 1.iso
/
connect
/
_j2
/
wvnsc926
/
wvpath.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-09-18
|
27KB
|
822 lines
/*
* wvpath.c
*
* based on ddlist example is MSDN (Copyright (c)1992 Kraig Brockschmidt)
*
* John S. Cooper
* 9/10/94
*/
#include <windows.h>
#include <windowsx.h>
#include "wvglob.h"
#include "winvn.h"
#pragma hdrstop
#include <dos.h>
#include <io.h> // for _access
#include <stdlib.h>
#include <stdio.h>
#include <direct.h>
#include <string.h>
/* forward declarations */
void DriveListInitialize(HWND, HWND);
UINT DriveType(UINT);
void DirectoryListInitialize(HWND, HWND, LPSTR);
void DriveDirDrawItem(LPDRAWITEMSTRUCT, BOOL);
void TransparentBlt(HDC, UINT, UINT, HBITMAP, COLORREF);
//Special ROP code for TransparentBlt.
#define ROP_DSPDxax 0x00E20746
/*
* DriveListInitialize
*
* Purpose:
* Resets and fills the given combobox with a list of current
* drives. The type of drive is stored with the item data.
*
* Parameters:
* hList HWND of the combobox to fill.
* hTempList HWND to use for finding drives.
*
* Return Value:
* None
*/
void DriveListInitialize(HWND hList, HWND hTempList)
{
struct find_t fi;
char ch;
UINT i, iItem;
UINT cch, cItems;
UINT iDrive, iType;
UINT iCurDrive;
char szDrive[10];
char szNet[64];
char szItem[26];
if (NULL==hList)
return;
//Clear out all the lists.
SendMessage(hList, CB_RESETCONTENT, 0, 0L);
SendMessage(hTempList, LB_RESETCONTENT, 0, 0L);
//Get available drive letters in the temp list
SendMessage(hTempList, LB_DIR, DDL_DRIVES | DDL_EXCLUSIVE, (LONG)(LPSTR)"*");
iCurDrive=_getdrive()-1; //Fix for zero-based drive indexing
/*
* Walk through the list of drives, parsing off the "[-" and "-]"
* For each drive letter parsed, add a string to the combobox
* composed of the drive letter and the volume label. We then
* determine the drive type and add that information as the item data.
*/
cItems=(int)SendMessage(hTempList, LB_GETCOUNT, 0, 0L);
for (i=0; i<cItems; i++)
{
SendMessage(hTempList, LB_GETTEXT, i, (LONG)(LPSTR)szDrive);
//Insure lowercase drive letters
AnsiLower(szDrive);
iDrive=szDrive[2]-'a';
iType=DriveType(iDrive); //See Below
if (iType < 2) //Skip non-existent drive B's
continue;
//Start the item string with the drive letter, color, and two spaces
wsprintf(szItem, "%c%s", szDrive[2], (LPSTR)": ");
/*
* For fixed or ram disks, append the volume label which we find
* using _dos_findfirst and attribute _A_VOLID.
*/
if (DRIVE_FIXED==iType || DRIVE_RAM==iType)
{
wsprintf(szDrive, "%c:\\*.*", szDrive[2]);
if (0==_dos_findfirst(szDrive, _A_VOLID, &fi))
{
//Convert volume to lowercase and strip any . in the name.
AnsiLower(fi.name);
//If a period exists, it has to be in position 8, so clear it.
ch=fi.name[8];
fi.name[8]=0;
lstrcat(szItem, fi.name);
//If we did have a broken volume name, append the last 3 chars
if ('.'==ch)
lstrcat(szItem, &fi.name[9]);
}
}
//For network drives, go grab the \\server\share for it.
if (DRIVE_REMOTE==iType)
{
szNet[0]=0;
cch=sizeof(szNet);
wsprintf(szDrive, "%c:", szDrive[2]);
AnsiUpper(szDrive);
WNetGetConnection((LPSTR)szDrive, (LPSTR)szNet, &cch);
AnsiLower(szNet);
lstrcat(szItem, szNet);
}
iItem=(int)SendMessage(hList, CB_ADDSTRING, 0, (LONG)(LPSTR)szItem);
SendMessage(hList, CB_SETITEMDATA, iItem, MAKELONG(iDrive, iType));
if (iDrive==iCurDrive)
SendMessage(hList, CB_SETCURSEL, iItem, 0L);
}
return;
}
/*
* DriveType
*
* Purpose:
* Augments the Windows API GetDriveType with a call to the CD-ROM
* extensions to determine if a drive is a floppy, hard disk, CD-ROM,
* RAM-drive, or networked drive.
*
* Parameters:
* iDrive UINT containing the zero-based drive index
*
* Return Value:
* UINT One of the following values describing the drive:
* DRIVE_FLOPPY, DRIVE_HARD, DRIVE_CDROM, DRIVE_RAM,
* DRIVE_NETWORK.
*/
UINT DriveType(UINT iDrive)
{
int iType;
BOOL fCDROM=FALSE;
BOOL fRAM=FALSE;
//Validate possible drive indices
if (0 > iDrive || 25 < iDrive)
return 0xFFFF;
iType=GetDriveType(iDrive);
/*
* Under Windows NT, GetDriveType returns complete information
* not provided under Windows 3.x which we now get through other
* means.
*/
#ifdef WIN32
return iType;
#else
//Check for CDROM on FIXED and REMOTE drives only
if (DRIVE_FIXED==iType || DRIVE_REMOTE==iType)
{
_asm
{
mov ax,1500h //Check if MSCDEX exists
xor bx,bx
int 2fh
or bx,bx //BX unchanged if MSCDEX is not around
jz CheckRAMDrive //No? Go check for RAM drive.
mov ax,150Bh //Check if drive is using CD driver
mov cx,iDrive
int 2fh
mov fCDROM,ax //AX if the CD-ROM flag
or ax,ax
jnz Exit //Leave if we found a CD-ROM drive.
CheckRAMDrive:
}
}
//Check for RAM drives on FIXED disks only.
if (DRIVE_FIXED==iType)
{
/*
* Check for RAM drive is done by reading the boot sector and
* looking at the number of FATs. Ramdisks only have 1 while
* all others have 2.
*/
_asm
{
push ds
mov bx,ss
mov ds,bx
sub sp,0200h //Reserve 512 bytes to read a sector
mov bx,sp //and point BX there.
mov ax,iDrive //Read the boot sector of the drive
mov cx,1
xor dx,dx
int 25h
add sp,2 //Int 25h requires our stack cleanup.
jc DriveNotRAM
mov bx,sp
cmp ss:[bx+15h],0f8h //Reverify fixed disk
jne DriveNotRAM
cmp ss:[bx+10h],1 //Check if there's only one FATs
jne DriveNotRAM
mov fRAM,1
DriveNotRAM:
add sp,0200h
pop ds
Exit:
//Leave fRAM untouched it's FALSE by default.
}
}
/*
* If either CD-ROM or RAM drive flags are set, return privately
* defined flags for them (outside of Win32). Otherwise return
* the type given from GetDriveType.
*/
if (fCDROM)
return DRIVE_CDROM;
if (fRAM)
return DRIVE_RAM;
//Drive B on a one drive system returns < 2 from GetDriveType.
return iType;
#endif
}
/*
* DirectoryListInitialize
*
* Purpose:
* Initializes strings in a listbox given a directory path. The first
* string in the listbox is the drive letter. The remaining items are
* each directory in the path completed with a listing of all sub-
* directories under the last directory in the path.
*
* Parameters:
* hList HWND of the listbox to fill.
* hTempList HWND of a listbox to use for directory enumerations.
* pszDir LPSTR of the path to use in initialization assumed
* to be at least _MAX_DIR long.
*
* Return Value:
* None
*/
void DirectoryListInitialize(HWND hList, HWND hTempList, LPSTR pszDir)
{
LPSTR psz, pszLast;
char ch;
char szDir[_MAX_DIR];
UINT cch, cItems;
UINT i, iItem, iIndent;
BOOL fFirst=TRUE;
if (NULL==hList || NULL==pszDir)
return;
//If the path ends in a \, strip the '\'
cch=lstrlen(pszDir);
if ('\\'==pszDir[cch-1])
pszDir[cch-1]=0;
//Clear out all the lists.
SendMessage(hList, WM_SETREDRAW, FALSE, 0L);
SendMessage(hList, LB_RESETCONTENT, 0, 0L);
SendMessage(hTempList, LB_RESETCONTENT, 0, 0L);
/*
* Walk through the path one \ at a time. At each one found,
* we add the string composed of the characters between it and
* the last \ found. We also make sure everything is lower case.
*/
pszLast=AnsiLower(pszDir);
//Save this for changing directories
SetWindowText(hList, pszDir);
//Save the directory appended with \*.*
wsprintf(szDir, "%s\\*.*", pszDir);
while (TRUE)
{
psz=_fstrchr(pszLast, '\\');
if (NULL!=psz)
{
/*
* Save the character here so we can NULL terminate. If this
* if the first entry, it's a drive root, so keep the \
*/
if (fFirst)
ch=*(++psz);
else
ch=*psz;
*psz=0;
}
else
{
//If we're looking at a drive only, then append a backslash
if (pszLast==pszDir && fFirst)
lstrcat(pszLast, "\\");
}
//Add the drive string--includes the last one where psz==NULL
iItem=(UINT)SendMessage(hList, LB_ADDSTRING, 0, (LONG)pszLast);
/*
* The item data here has in the HIWORD the bitmap to use for
* the item with the LOWORD containing the indentation. The
* bitmap is IDB_FOLDEROPEN for anything above the current
* directory (that is, c:\foo is above than c:\foo\bar),
* IDB_FOLDERCLOSED for anything below the current, and
* IDB_FOLDEROPENSELECT for the current directory.
*/
i=(NULL!=psz) ? IDB_FOLDEROPEN : IDB_FOLDEROPENSELECT;
SendMessage(hList, LB_SETITEMDATA, iItem, MAKELONG(iItem, i));
if (NULL==psz)
break;
//Restore last character.
*psz=ch;
psz+=(fFirst) ? 0 : 1;
fFirst=FALSE;
pszLast=psz;
}
/*
* Now that we have the path in, enumerate the subdirectories here
* and place them in the list at the indentation iItem+1 since iItem
* was the index of the last item in the path added to the list.
*
* To enumerate the directories, we send LB_DIR to an alternate
* listbox. On return, we have to parse off the brackets around
* those directory names before bringing them into this listbox.
*/
iIndent=iItem+1;
//Get available directories; szDir is pszDir\*.*
SendMessage(hTempList, LB_DIR, DDL_DIRECTORY | DDL_EXCLUSIVE
, (LONG)(LPSTR)szDir);
cItems=(int)SendMessage(hTempList, LB_GETCOUNT, 0, 0L);
for (i=0; i<cItems; i++)
{
cch=(UINT)SendMessage(hTempList, LB_GETTEXT, i, (LONG)(LPSTR)szDir);
//Skip directories beginning with . (skipping . and ..)
if ('.'==szDir[1])
continue;
//Remove the ending ']'
szDir[cch-1]=0;
//Add the string to the real directory list.
iItem=(UINT)SendMessage(hList, LB_ADDSTRING, 0
, (LONG)(LPSTR)(szDir+1));
SendMessage(hList, LB_SETITEMDATA, iItem
, MAKELONG(iIndent, IDB_FOLDERCLOSED));
}
//Force a listbox repaint.
SendMessage(hList, WM_SETREDRAW, TRUE, 0L);
InvalidateRect(hList, NULL, TRUE);
/*
* If there's a vertical scrollbar, then we've added more items than
* are visible at once. To meet the UI specifications, we're supposed
* to make the next directory up the top visible one.
*/
GetScrollRange(hList, SB_VERT, (LPINT)&i, (LPINT)&iItem);
if (!(0==i && 0==iItem))
SendMessage(hList, LB_SETTOPINDEX, max((int)(iIndent-2), 0), 0L);
//Last thing is to set the current directory as the selection
SendMessage(hList, LB_SETCURSEL, iIndent-1, 0L);
return;
}
/*
* DriveDirDrawItem
*
* Purpose:
* Handles WM_DRAWITEM for both drive and directory listboxes.
*
* Parameters:
* pDI LPDRAWITEMSTRUCT passed with the WM_DRAWITEM message.
* fDrive BOOL TRUE to draw a drive, FALSE to draw directory.
*
* Return Value:
* None
*/
void DriveDirDrawItem(LPDRAWITEMSTRUCT pDI, BOOL fDrive)
{
char szItem[40];
int iType=0;
int iIndent=0;
UINT uMsg;
DWORD dw;
BITMAP bm;
COLORREF crText, crBack;
HBITMAP hBmp;
if ((int)pDI->itemID < 0)
return;
if (fDrive)
dw=SendMessage(pDI->hwndItem, CB_GETITEMDATA, pDI->itemID, 0L);
//Get the text string for this item (controls have different messages)
uMsg=(fDrive) ? CB_GETLBTEXT : LB_GETTEXT;
SendMessage(pDI->hwndItem, uMsg, pDI->itemID, (LONG)(LPSTR)szItem);
if ((ODA_DRAWENTIRE | ODA_SELECT) & pDI->itemAction)
{
if (ODS_SELECTED & pDI->itemState)
{
//Select the appropriate text colors
crText=SetTextColor(pDI->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
crBack=SetBkColor(pDI->hDC, GetSysColor(COLOR_HIGHLIGHT));
}
/*
* References to the two bitmap arrays here are the only external
* dependencies of this code. To keep it simple, we didn't use
* a more complex scheme like putting all the images into one bitmap.
*/
if (fDrive)
{
//For drives, get the type, which determines the bitmap.
iType=(int)HIWORD(dw);
hBmp=DiskBitmaps[iType-IDB_DRIVEMIN];
}
else
{
//For directories, indentation level is 4 pixels per indent.
iIndent=4*(1+LOWORD(pDI->itemData));
hBmp=FolderBitmaps[HIWORD(pDI->itemData)-IDB_FOLDERMIN];
}
GetObject(hBmp, sizeof(bm), &bm);
/*
* Paint the text and the rectangle in whatever colors. If
* we're drawing drives, iIndent is zero so it's ineffective.
*/
ExtTextOut(pDI->hDC, pDI->rcItem.left+bm.bmWidth+4+iIndent
, pDI->rcItem.top, ETO_OPAQUE, &pDI->rcItem, szItem
, lstrlen(szItem), (LPINT)NULL);
//Go draw the bitmap we want.
TransparentBlt(pDI->hDC, pDI->rcItem.left+iIndent
, pDI->rcItem.top, hBmp, RGB(0,0,255));
//Restore original colors if we changed them above.
if (ODS_SELECTED & pDI->itemState)
{
SetTextColor(pDI->hDC, crText);
SetBkColor(pDI->hDC, crBack);
}
}
if ((ODA_FOCUS & pDI->itemAction) || (ODS_FOCUS & pDI->itemState))
DrawFocusRect(pDI->hDC, &pDI->rcItem);
return;
}
/*
* TransparentBlt
*
* Given a DC, a bitmap, and a color to assume as transparent in that
* bitmap, BitBlts the bitmap to the DC letting the existing background
* show in place of the transparent color.
*
* Parameters:
* hDC HDC on which to draw.
* x, y UINT location at which to draw the bitmap
* hBmp HBITMIP to draw
* cr COLORREF to consider as transparent.
*/
void TransparentBlt(HDC hDC, UINT x, UINT y, HBITMAP hBmp, COLORREF cr)
{
HDC hDCSrc, hDCMid, hMemDC;
HBITMAP hBmpMono, hBmpT;
HBRUSH hBr, hBrT;
COLORREF crBack, crText;
BITMAP bm;
if (NULL==hBmp)
return;
GetObject(hBmp, sizeof(bm), &bm);
//Get three intermediate DC's
hDCSrc=CreateCompatibleDC(hDC);
hDCMid=CreateCompatibleDC(hDC);
hMemDC=CreateCompatibleDC(hDC);
SelectObject(hDCSrc, hBmp);
//Create a monochrome bitmap for masking
hBmpMono=CreateCompatibleBitmap(hDCMid, bm.bmWidth, bm.bmHeight);
SelectObject(hDCMid, hBmpMono);
//Create a middle bitmap
hBmpT=CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight);
SelectObject(hMemDC, hBmpT);
//Create a monochrome mask where we have 0's in the image, 1's elsewhere.
crBack=SetBkColor(hDCSrc, cr);
BitBlt(hDCMid, 0, 0, bm.bmWidth, bm.bmHeight, hDCSrc, 0, 0, SRCCOPY);
SetBkColor(hDCSrc, crBack);
//Put the unmodified image in the temporary bitmap
BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDCSrc, 0, 0, SRCCOPY);
//Create an select a brush of the background color
hBr=CreateSolidBrush(GetBkColor(hDC));
hBrT=SelectObject(hMemDC, hBr);
//Force conversion of the monochrome to stay black and white.
crText=SetTextColor(hMemDC, 0L);
crBack=SetBkColor(hMemDC, RGB(255, 255, 255));
/*
* Where the monochrome mask is 1, Blt the brush; where the mono mask
* is 0, leave the destination untouches. This results in painting
* around the image with the background brush. We do this first
* in the temporary bitmap, then put the whole thing to the screen.
*/
BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDCMid, 0, 0, ROP_DSPDxax);
BitBlt(hDC, x, y, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0, SRCCOPY);
SetTextColor(hMemDC, crText);
SetBkColor(hMemDC, crBack);
SelectObject(hMemDC, hBrT);
DeleteObject(hBr);
DeleteDC(hMemDC);
DeleteDC(hDCSrc);
DeleteDC(hDCMid);
DeleteObject(hBmpT);
DeleteObject(hBmpMono);
return;
}
/*
* WinVnSelectPathDialogDlg
*
* Handles the dialog that displays a drive and directory owner-draw
* combobox and listbox, respectiviely. This procedure handles only
* the WM_INITDIALOG and WM_DRAWITEM messages,dispatching them to
* alternate functions that handle each message for each list.
*
*/
BOOL FAR PASCAL WinVnSelectPathDlg(HWND hDlg,unsigned iMessage,WPARAM wParam,LPARAM lParam)
{
char cwd[_MAX_PATH];
WORD wID;
WORD wCode;
HWND hWndMsg;
hWndMsg=(HWND)(UINT)lParam;
wID=LOWORD(wParam);
#ifdef WIN32
wCode=HIWORD(wParam);
#else
wCode=HIWORD(lParam);
#endif
switch (iMessage)
{
case WM_INITDIALOG:
ShowWindow(hDlg, SW_SHOW);
UpdateWindow(hDlg);
DriveListInitialize(GetDlgItem(hDlg, ID_DRIVELIST), GetDlgItem(hDlg, ID_TEMPLIST));
if (lParam && _access((char *)lParam, 0) >= 0) {
strcpy (cwd, (char *)lParam);
_chdir(cwd);
} else
_getcwd(cwd, _MAX_PATH);
DirectoryListInitialize(GetDlgItem(hDlg, ID_DIRECTORYLIST), GetDlgItem(hDlg, ID_TEMPLIST), cwd);
return TRUE;
case WM_MEASUREITEM:
{
static int cyItem=-1; //Height of a listbox item
LPMEASUREITEMSTRUCT pMI;
pMI=(LPMEASUREITEMSTRUCT)lParam;
if (-1==cyItem)
{
HFONT hFont;
HDC hDC;
TEXTMETRIC tm;
BITMAP bm;
/*
* Attempt to get the font of the dialog. However,
* on the first attempt in the life of the dialog,
* this could fail; in that case use the system font.
*/
hFont=(HANDLE)(UINT)SendMessage(hDlg, WM_GETFONT, 0, 0L);
if (NULL==hFont)
hFont=GetStockObject(SYSTEM_FONT);
hDC=GetDC(hDlg);
hFont=SelectObject(hDC, hFont);
/*
* Item height is the maximum of the font height and the
* bitmap height. We know that all bitmaps are the same
* size, so we just get information for one of them.
*/
GetTextMetrics(hDC, &tm);
GetObject(FolderBitmaps[0], sizeof(bm), &bm);
cyItem=max(bm.bmHeight, tm.tmHeight);
ReleaseDC(hDlg, hDC);
}
pMI->itemHeight=cyItem;
}
break;
case WM_DRAWITEM:
//Go draw the appropriate item and bitmap.
DriveDirDrawItem((LPDRAWITEMSTRUCT)lParam, (ID_DRIVELIST==wID));
//Prevent default actions in listboxes (drawing focus rect)
return TRUE;
case WM_COMMAND:
switch (wID)
{
case ID_DIRECTORYLIST:
if (LBN_DBLCLK==wCode)
{
UINT i;
DWORD dw;
char szDir[_MAX_PATH];
LPSTR psz;
/*
* On double-click, change directory and reinit the
* listbox. But all we stored in the string was
* the directory's single name, so we use the bitmap
* type to tell if we're below the current directory
* (in which case we just chdir to our name) or above
* (in which case we prepend "..\"'s as necessary.
*/
i=(UINT)SendMessage(hWndMsg, LB_GETCURSEL, 0, 0L);
dw=SendMessage(hWndMsg, LB_GETITEMDATA, i, 0L);
/*
* If out bitmap is IDB_FOLDERCLOSED or the root,
* then just . If we're IDB_FOLDEROPENSELECT,
* don't do anything. If we're IDB_FOLDEROPEN then
* we get the full current path and truncate it
* after the directory to which we're switching.
*/
if (IDB_FOLDEROPENSELECT==HIWORD(dw))
break;
//Get get the directory for sub-directory changes.
SendMessage(hWndMsg, LB_GETTEXT, i, (LONG)(LPSTR)cwd);
if (IDB_FOLDEROPEN==HIWORD(dw) && 0!=i)
{
//Get the current path and find us in this path
GetWindowText(hWndMsg, szDir, sizeof(szDir));
psz=_fstrstr(szDir, cwd);
//Null terminate right after us.
*(psz+lstrlen(cwd))=0;
//Get this new directory in the right place
lstrcpy(cwd, szDir);
}
//chdir has a nice way of validating for us.
if (0==_chdir(cwd))
{
//Get the new full path.
_getcwd(cwd, _MAX_PATH);
DirectoryListInitialize(hWndMsg
, GetDlgItem(hDlg, ID_TEMPLIST), cwd);
}
}
break;
case ID_DRIVELIST:
if (CBN_SELCHANGE==wCode)
{
UINT i, iCurDrive;
char szDrive[18]; //Enough for drive:volume
//Get the first letter in the current selection
i=(UINT)SendMessage(hWndMsg, CB_GETCURSEL, 0, 0L);
SendMessage(hWndMsg, CB_GETLBTEXT
, i, (LONG)(LPSTR)szDrive);
iCurDrive=_getdrive(); //Save in case of restore
/*
* Attempt to set the drive and get the current
* directory on it. Both must work for the change
* to be certain. If we are certain, reinitialize
* the directories. Note that we depend on drives
* stored as lower case in the combobox.
*/
if (0==_chdrive((int)(szDrive[0]-'a'+1))
&& NULL!=_getcwd(cwd, _MAX_PATH))
{
DirectoryListInitialize(
GetDlgItem(hDlg, ID_DIRECTORYLIST),
GetDlgItem(hDlg, ID_TEMPLIST), cwd);
//Insure that the root is visible (UI guideline)
SendDlgItemMessage(hDlg, ID_DIRECTORYLIST
, LB_SETTOPINDEX, 0, 0L);
break;
}
//Changing drives failed so restore drive and selection
_chdrive((int)iCurDrive);
wsprintf(szDrive, "%c:", (char)(iCurDrive+'a'-1));
i=(UINT)SendMessage(hWndMsg, CB_SELECTSTRING
, (WPARAM)-1, (LONG)(LPSTR)szDrive);
}
break;
case IDOK:
_getcwd(DialogString, MAXINTERNALLINE);
EndDialog(hDlg, TRUE);
break;
case IDCANCEL:
EndDialog (hDlg, FALSE);
break;
}
break;
default:
break;
}
return FALSE;
}